package slap.http;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jodd.io.FastByteArrayOutputStream;

import slap.Slap;
import slap.exception.UnexpectedException;
import slap.util.Time;
import slap.util.Utils;

public class Response {
	protected static final Logger logger = LoggerFactory.getLogger(Response.class);
    public Integer status = 200;
    public String contentType = "text/html";
    public Map<String, Header> headers = new HashMap<String, Header>(16);
    public Map<String, Cookie> cookies = new HashMap<String, Cookie>(16);
    public FastByteArrayOutputStream out;
    public Object direct;
    
    public static ThreadLocal<Response> current = new ThreadLocal<Response>();
    
    public static Response current() {
        return current.get();
    }
    
    public String header(String name) {
        for (String key : headers.keySet()) {
            if (key.toLowerCase().equals(name.toLowerCase())) {
                if (headers.get(key) != null) {
                    return headers.get(key).value();
                }
            }
        }
        return null;
    }

    public void setHeader(String name, String value) {
        Header h = new Header();
        h.name = name;
        h.value = value;
        headers.put(name, h);
    }

    public void setContentTypeIfNotSet(String contentType) {
        if (this.contentType == null) {
            this.contentType = contentType;
        }
    }
    
    public void enableGZipTransfer(){
    	setHeader(Header.Names.CONTENT_ENCODING, Header.Values.GZIP);
    }
    
    public void disableGZipTransfer(){
    	headers.remove(Header.Names.CONTENT_ENCODING);
    }
    
    public void setCookie(String name, String value) {
        setCookie(name, value, null, "/", null, false);
    }

    public void removeCookie(String name) {
        removeCookie(name, "/");
    }

    public void removeCookie(String name, String path) {
        setCookie(name, "", null, path, 0, false);
    }

    public void setCookie(String name, String value, String duration) {
        setCookie(name, value, null, "/", Time.parseDuration(duration), false);
    }

    public void setCookie(String name, String value, String domain, String path, Integer maxAge, boolean secure) {
        setCookie(name, value, domain, path, maxAge, secure, false);
    }

    public void setCookie(String name, String value, String domain, String path, Integer maxAge, boolean secure, boolean httpOnly) {
        if (cookies.containsKey(name) && cookies.get(name).path.equals(path) && ((cookies.get(name).domain == null && domain == null) || (cookies.get(name).domain.equals(domain)))) {
            cookies.get(name).value = value;
            if (maxAge != null) {
                cookies.get(name).maxAge = maxAge;
            }
            cookies.get(name).secure = secure;
        } else {
            Cookie cookie = new Cookie();
            cookie.name = name;
            cookie.value = value;
            cookie.path = path;
            cookie.secure = secure;
            cookie.httpOnly = httpOnly;
            if (domain != null) {
                cookie.domain = domain;
            } else {
                cookie.domain = Cookie.defaultDomain;
            }
            if (maxAge != null) {
                cookie.maxAge = maxAge;
            }
            cookies.put(name, cookie);
        }
    }

    public void cacheFor(String duration) {
        int maxAge = Time.parseDuration(duration);
        setHeader("Cache-Control", "max-age=" + maxAge);
    }

    /**
     * Add cache-control headers
     * @param duration Ex: 3h
     */
    public void cacheFor(String duration, long lastModified) {
        int maxAge = Time.parseDuration(duration);
        setHeader("Cache-Control", "max-age=" + maxAge);
        setHeader("Last-Modified", Time.httpFormatter.format(new Date(lastModified)));
    }

    /**
     * Add headers to allow cross-domain requests. Be careful, a lot of browsers don't support
     * these features and will ignore the headers. Refer to the browsers' documentation to
     * know what versions support them.
     * @param allowOrigin a comma separated list of domains allowed to perform the x-domain call, or "*" for all.
     */
    public void accessControl(String allowOrigin) {
        accessControl(allowOrigin, null, false);
    }

    /**
     * Add headers to allow cross-domain requests. Be careful, a lot of browsers don't support
     * these features and will ignore the headers. Refer to the browsers' documentation to
     * know what versions support them.
     * @param allowOrigin a comma separated list of domains allowed to perform the x-domain call, or "*" for all.
     * @param allowCredentials Let the browser send the cookies when doing a x-domain request. Only respected by the browser if allowOrigin != "*"
     */
    public void accessControl(String allowOrigin, boolean allowCredentials) {
        accessControl(allowOrigin, null, allowCredentials);
    }

    /**
     * Add headers to allow cross-domain requests. Be careful, a lot of browsers don't support
     * these features and will ignore the headers. Refer to the browsers' documentation to
     * know what versions support them.
     * @param allowOrigin a comma separated list of domains allowed to perform the x-domain call, or "*" for all.
     * @param allowMethods a comma separated list of HTTP methods allowed, or null for all.
     * @param allowCredentials Let the browser send the cookies when doing a x-domain request. Only respected by the browser if allowOrigin != "*"
     */
    public void accessControl(String allowOrigin, String allowMethods, boolean allowCredentials) {
        setHeader("Access-Control-Allow-Origin", allowOrigin);
        if (allowMethods != null) {
            setHeader("Access-Control-Allow-Methods", allowMethods);
        }
        if (allowCredentials == true) {
            if (allowOrigin.equals("*")) {
                logger.warn("Response.accessControl: When the allowed domain is \"*\", Allow-Credentials is likely to be ignored by the browser.");
            }
            setHeader("Access-Control-Allow-Credentials", "true");
        }
    }

    public void print(Object o) {
        try {
            out.write(o.toString().getBytes("utf-8"));
        } catch (IOException ex) {
            throw new UnexpectedException("UTF-8 problem ?", ex);
        }
    }

    public void reset() {
        out.reset();
    }
}